from flask_restful import Resource
from flask import g, current_app, request
from comment.models.user import User
from comment.models.account import Account
from comment.utils.SendMessage import send_message
from financial.resource.user.constants import SMS_CODE_EXPIRES, INVITE_MONEY
import json
import random
from comment.utils.financial_Redis import fr
from flask_restful import reqparse
from comment.models import db
from comment.utils.tokens_pyjwt import generate_tokens,verify_tokens
from comment.utils.decorators import login_required


class Login(Resource):
    '''
    登录
    '''

    def post(self):
        rq=reqparse.RequestParser()
        rq.add_argument('username',required=True)
        rq.add_argument('password',required=True)
        req=rq.parse_args()
        username=req.username       #用户名
        password=req.password       #密码
        user=User.query.filter(User.username==username).first()
        if user:
            #验证密码是否一致
            if user.check_password(password):
                #todo 用户登录成功，生成一个token，以便于后面去认证token
                token=generate_tokens(user.id)
                current_app.logger.info(token)
                current_app.logger.info('测试验证token',verify_tokens(token))
                return {'token':token}
        return {'message':'用户名或者密码错误','code':201}


class LoginOut(Resource):
    '''
    退出登录
    '''
    #todo 使用了登录拦截的装饰器,下面所有的视图函数都加上了登录拦截
    method_decorators = [login_required]

    #todo 在指定的视图方法下加登录拦截
    # method_decorators ={
    #     'post':[login_required],
    #     'get':[login_required]
    # }

    def post(self):
        if g.user_id:
            g.user_id=None
        return {'msg':'成功退出登录'}

    def get(self):
        pass

class UserAvatar(Resource):
    '''
    管理用户头像的
    '''
    #上传头像一定需要登陆
    method_decorators = [login_required]
    def post(self):
        '''
        上传用户头像图片
        :return:
        '''
        #用户上传的图片数据
        img_data=request.files['file']

        id=g.user_id
        user=User.query.filter(User.id==id).first()

        #设置用户头像保存的路径
        img_dir=current_app.config['AVATAR_DIR']
        #设置头像文件名
        img_name=str(id)+"_"+img_data.filename
        file_path=img_dir + '/' + img_name
        #保存文件
        img_data.save(file_path)
        #在数据库中保存用户图像图片的文件名
        if user:
            user.avatar=img_name
            db.session.commit()
            return {'msg':'上传头像图片成功','avator':img_name}



# class RegisterUser(Resource):
#     '''
#     用户的注册
#     '''
#
#     def post(self):
#         rq = reqparse.RequestParser()
#         rq.add_argument('phone', required=True)
#         rq.add_argument('username', required=True)
#         rq.add_argument('password', required=True)
#         rq.add_argument('code', required=True)
#         rq.add_argument('invite_code', required=False)
#         args = rq.parse_args()
#         username = args.username
#         password = args.password
#         phone = args.phone
#         code = args.code
#         invite_code = args.invite_code
#         # 验证用户名是否唯一
#         user = User.query.filter(User.username == username).first()
#         if user:
#             current_app.logger.info('{}:用户名已经存在，请更换用户名'.format(username))
#             return {'message': '用户名重复', 'code': 201}
#         # 从redis中获取短信验证码
#         real_code = fr.get('registerCode:{}'.format(phone))
#         if not real_code or real_code.decode() != code:  # 数据库中没有code或者存储的code与参数不一致
#             current_app.logger.info('验证码错误或者失效')
#             return {'message': '验证码错误或者失效', 'code': 201}
#
#         # 把用户保存在mysql数据库中
#         user = User(username=username, phone=phone, pwd=password)
#
#         # 验证和关联邀请码
#         if invite_code:
#             self.check_invite(user, invite_code)
#
#         try:  # 需要用到数据库事务处理
#             db.session.add(user)
#             db.session.flush()  # todo 把数据插入到数据库的缓冲区（得到自增的id），并不是插入到数据库中
#             account = Account(userId=user.id)  # 创建当前用户的账户对象。
#             db.session.add(account)
#             db.session.commit()
#             return {'msg': 'success'}
#         except Exception as e:
#             current_app.logger.error(e)
#             db.session.rollback()  # 回滚操作
#             return {'message': '用户注册时，插入数据库失败', 'code': 201}
#
#     # 验证和关联邀请码的
#     def check_invite(self, user, invite_code):
#         code = invite_code.strip()
#         invite_user = User.query.filter(User.inviteId == code).first()  # 邀请用户
#         if invite_user:
#             user.invite_user_id = invite_user.id  # 如果邀请码有效，则把这2个用户关联一下
#             invite_user.accountInfo.discount += INVITE_MONEY  # 邀请用户的账户中增加50元的代金券
#             invite_user.sumFriends+=1       #邀请的记录数增加1

class IsExistPhone(Resource):
    '''
    判断手机号是否存在
    '''

    def post(self):  # 如果是post请求，请求的参数往往会封装成json对象
        phone = request.form.get('phone')
        user = User.query.filter(User.phone == phone).first()
        if user:
            return {'message': '此手机号已经注册过，请更换手机号码', 'code': 201}
        return {'msg': 'success'}


class SMSCode(Resource):
    '''
    发送手机短信，验证手机号码
    '''

    def get(self):  ##如果是get请求，请求的参数往往是：参数名+参数
        phone = request.args.get('phone').strip()
        # 生成一个随机的验证码
        code = random.randint(1000, 9999)
        result = send_message('1', mobile=phone, datas=(code, '1'))
        # 将res转化为字典格式的数据
        re_dict = json.loads(result)
        if re_dict:
            current_app.logger.info(f'给手机号:{phone},发送短信成功')
            # todo 验证码需要存起来，存在redis缓冲数据库中,还需要把验证码再注册的请求中去验证
            # todo redis中存放的是字节类型的数据，有时效性
            # todo setex有3个参数，参数1：键，参数2：时效，参数3：具体的值
            fr.setex('registerCode:{}'.format(phone), SMS_CODE_EXPIRES, code)
            return {'msg': 'success', 'smsCode': code}

        else:
            return {'message': '此手机号{}发送短信失败'.format(phone), 'code': 201}



class RegisterUser(Resource):
    def post(self):
        rq=reqparse.RequestParser()
        rq.add_argument('phone',required=True)
        rq.add_argument('username',required=True)
        rq.add_argument('password',required=True)
        rq.add_argument('code',required=True)
        rq.add_argument('invite_code',required=False)
        req=rq.parse_args()
        self.phone=req.phone
        self.username=req.username
        self.password=req.password
        self.code=req.code
        self.invite_code=req.invite_code
        user=User.query.filter(User.phone==self.phone).first()
        if user:
            current_app.logger.info('手机号已经存在')
            return {'message':'手机号已经存在'}
        user=User.query.filter(User.username==self.username).first()
        if user:
            current_app.logger.info('用户名已经存在')
            return {'message': '用户名已经存在'}

        real_code=fr.get('registerCode:{}'.format(self.phone))
        if not real_code or real_code.decode()!=self.code:
            current_app.logger.info('验证码错误')
            return {'message':'验证码错误'}


        user=User(username=self.username,pwd=self.password,phone=self.phone)

        #验证邀请码
        if self.invite_code:
            self.check_invite(user,invite_code)

        try:
            #需要用到数据库事务处理
            db.session.add(user)
            db.session.flush()      #todo 把数据插入的数据库的缓冲区(目的得到自增的id)，并不是插入到数据库中
            #todo 创建账户对象,账户id和用户id是一一对应的
            account=Account(userId=user.id)
            db.session.add(account)
            db.session.commit()
            return {'msg':'success'}
        except Exception as e:
            current_app.logger.info(e)
            db.session.rollback()       #回滚操作
            return {'message': '用户注册时，插入数据库失败', 'code': 201}




    def check_invite(self,user,invite_code):
        code=invite_code.strip()
        invite_user=User.query.filter(User.inviteId==code).first() #用户输入的邀请码和邀请用户数据库中的邀请码比对
        if invite_user:
            user.invite_user_id=invite_user.id  #todo 2个用户关联下 invite_user.id:邀请用户的id（例：张三邀请李四，张三的id）
            invite_user.sumFriends+=1       #todo 张三的数据库中邀请用户+1
            invite_user.accountInfo.discount+=INVITE_MONEY  #todo 邀请用户（张三）的账户增加50元的代金券










